package fox.framework.rpc.client.node.rule;

import fox.framework.rpc.client.node.RpcMetadata;
import fox.framework.rpc.client.node.RpcNode;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author cuichao
 * @Description: RoundRobinRule
 * @Date: create in 2021/1/31 17:19
 */
public class RoundRobinRule implements Rule {

    private AtomicInteger counter;


    public RoundRobinRule() {
        this.counter = new AtomicInteger(0);
    }

    @Override
    public RpcNode choose(RpcMetadata metadata) {
        
        int i= 0;
        //retry 10's

        while (i++ < 10){
            List<RpcNode> nodes = metadata.getAvailableNodes();

            if(nodes == null || nodes.isEmpty()){
                return null;
            }

            int position = incrementAndGet(nodes.size());

            if(position >= nodes.size()){
                Thread.yield();
                continue;
            }

            RpcNode node = nodes.get(position);

            if(node.getState() > 0){
               continue;
            }

            return node;
        }


        return null;
    }


    protected int incrementAndGet(int limit) {
        for (;;) {
            int current = counter.get();
            int next = (current + 1) % limit;
            if (counter.compareAndSet(current, next)){
                return next;
            }
        }
    }
}
